package com.vision.sales.sv.serv;

import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vision.core.cm.db.data.Company;
import com.vision.core.cm.exception.RpcException;
import com.vision.core.sv.db.CustomSessionFactoryBean;
import com.vision.core.sv.db.mgr.CompanyManager;
import com.vision.core.sv.db.mgr.DataManager;
import com.vision.core.sv.db.mgr.ISimpleCriteria;
import com.vision.core.sv.db.mgr.SimpleCriteria;
import com.vision.core.sv.serv.BaseRpcServlet;
import com.vision.core.sv.serv.util.ServletUtils;
import com.vision.sales.cm.data.SalesPermissions;
import com.vision.sales.cm.data.TransactionStatus;
import com.vision.sales.cm.db.data.Customer;
import com.vision.sales.cm.db.data.SalesInvoice;
import com.vision.sales.sv.db.mgr.CustomerManager;
import com.vision.sales.sv.db.mgr.SalesInvoiceManager;
import com.vision.sales.sv.report.ReportWriter;

/**
 * 
 * @author Mark
 *
 */
public class PrintIndividualSOAServlet extends BaseRpcServlet {

	private static final long serialVersionUID = 1L;
	
	private static final Logger log = LoggerFactory.getLogger(PrintIndividualSOAServlet.class);
	
	private DataManager<Company> companyManager;
	private DataManager<Customer> customerManager;
	private DataManager<SalesInvoice> invoiceManager;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			ServletUtils.checkPermissions(SalesPermissions.ViewIndividualSOAReport);
		} catch (RpcException e) {
			resp.sendError(HttpServletResponse.SC_FORBIDDEN, "You are not authorized to perform this operation.");
			return;
		}
		
		// Parameters --
		log.debug("Parsing parameters from URL...");
		IndividualSOAParams params = new IndividualSOAParams(req);
		if (params.error != null) {
			resp.sendError(HttpServletResponse.SC_BAD_REQUEST, params.error);
			return;
		}
		
		try {
			String path = getServletContext().getRealPath("/") + "templates/IndividualSOA.jrxml";
			
			log.debug("Loading JRXML file...");
			JasperDesign design = JRXmlLoader.load(path);
			
			log.debug("Compiling report...");
			JasperReport report = JasperCompileManager.compileReport(design);
			
			log.debug("Creating data source...");
			JRDataSource jrds = createDataSource(params);
			
			Map<String, Object> parameters = new HashMap<String, Object>();
			parameters.put(JRParameter.REPORT_DATA_SOURCE, jrds);
			
			log.debug("Filling report with data...");
			JasperPrint print = JasperFillManager.fillReport(report, parameters);

			log.debug("Sending report to client...");
			ReportWriter.write(print, "IndividualSOA", resp);
		} catch (JRException e) {
			log.error(e.getMessage(), e);
			resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error was encountered and the server was unable to process the request.");
		}
	}

	@SuppressWarnings("unchecked")
	private JRDataSource createDataSource(IndividualSOAParams params) {
		companyManager = new CompanyManager();
		companyManager.setSessionFactory(CustomSessionFactoryBean.getFactory());
		
		customerManager = new CustomerManager();
		customerManager.setSessionFactory(CustomSessionFactoryBean.getFactory());
		
		invoiceManager = new SalesInvoiceManager();
		invoiceManager.setSessionFactory(CustomSessionFactoryBean.getFactory());
		
		Company company = companyManager.getById(params.companyId);
		Customer customer = customerManager.getById(params.customerId);
		
		ISimpleCriteria crit = SimpleCriteria.forClass(SalesInvoice.class);
		crit.eq("status", TransactionStatus.POSTED);
		crit.eq("customer.id", customer.getId());
		crit.between("date", params.startDate, params.endDate);
		
		List<SalesInvoice> invoices = invoiceManager.getTemplate().findByCriteria(crit.getDetached());
		
		return new IndividualSOADataSource(company, customer, params.startDate, params.endDate, invoices);
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	static class IndividualSOAParams extends SalesReportParams {
		
		long companyId;
		
		long customerId;
		
		Date startDate;
		Date endDate;

		public IndividualSOAParams(HttpServletRequest req) {
			super(req);
			
			try {
				companyId = Long.parseLong(req.getParameter("company"));
			} catch (Exception e) {
				error = "Unable to determine company.";
				return;
			}
			
			try {
				customerId = Long.parseLong(req.getParameter("customer"));
			} catch (Exception e) {
				error = "Unable to determine customer.";
				return;
			}
			
			try {
				startDate = yyyyMMdd.parse(req.getParameter("start"));
			} catch (Exception e) {
				error = "Unable to determine start date.";
				return;
			}
			
			try {
				endDate = yyyyMMdd.parse(req.getParameter("end"));
			} catch (Exception e) {
				error = "Unable to determine end date.";
				return;
			}
		}
		
	}

	static class IndividualSOADataSource extends JRBeanCollectionDataSource {
		
		Company company;
		Customer customer;
		Date startDate;
		Date endDate;

		public IndividualSOADataSource(Company company, Customer customer, Date startDate, Date endDate, Collection<SalesInvoice> beanCollection) {
			super(beanCollection);
			
			this.company = company;
			this.customer = customer;
			this.startDate = startDate;
			this.endDate = endDate;
		}
		
		@Override
		public Object getFieldValue(Object bean, JRField field) throws JRException {
			String name = field.getName();
			
			if (name.startsWith("company.")) {
				name = name.replace("company.", "");
				return super.getBeanProperty(company, name);
			}
			
			if (name.startsWith("customer.")) {
				name = name.replace("customer.", "");
				return super.getBeanProperty(customer, name);
			}
			
			if ("startDate".equals(name)) {
				return startDate;
			}
			
			if ("endDate".equals(name)) {
				return endDate;
			}
			
			if (name.startsWith("invoice.")) {
				name = name.replace("invoice.", "");
				return super.getBeanProperty(bean, name);
			}
			
			return super.getFieldValue(bean, field);
		}
		
	}
	
}
